package com.night.icm.service.base.service;

import com.github.wenhao.jpa.PredicateBuilder;
import com.github.wenhao.jpa.Specifications;
import com.night.icm.common.exception.NoSuchDataException;
import com.night.icm.common.jpa.PageHelper;
import com.night.icm.common.service.PageDataUtil;
import com.night.icm.common.utils.PageDataDTO;
import com.night.icm.common.utils.SimpleDataDTO;
import com.night.icm.model.base.ClassDTO;
import com.night.icm.persistence.base.entity.Academy;
import com.night.icm.persistence.base.entity.Class;
import com.night.icm.persistence.base.entity.Profession;
import com.night.icm.persistence.base.repository.AcademyRepository;
import com.night.icm.persistence.base.repository.ClassRepository;
import com.night.icm.persistence.base.repository.ProfessionRepository;
import com.night.icm.service.base.mapper.ClassMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

/**
 * ClassServiceImpl
 *
 * @author Liao ZhiYong
 * @date 2020/1/28
 */
@Service
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class ClassServiceImpl implements ClassService {

    private final ClassRepository classRepository;
    private final ClassMapper classMapper;
    private final AcademyRepository academyRepository;
    private final ProfessionRepository professionRepository;

    @Autowired
    public ClassServiceImpl(ClassRepository classRepository, ClassMapper classMapper, AcademyRepository academyRepository, ProfessionRepository professionRepository) {
        this.classRepository = classRepository;
        this.classMapper = classMapper;
        this.academyRepository = academyRepository;
        this.professionRepository = professionRepository;
    }


    /**
     * 分页查询班级
     *
     * @param page         页号，从0开始
     * @param size         每页纪录条数
     * @param sort         排序字段, 例如：字段1,asc,字段2,desc
     * @param code         班级编号
     * @param name         班级名称
     * @param grade        年级
     * @param academyId    学院id
     * @param professionId 专业id
     * @return 班级信息
     */
    @Override
    public PageDataDTO<ClassDTO> findOnePage(int page, int size, String sort, String code, String name, String grade, String academyId, String professionId) {
        grade = grade == null ? "" : grade;
        PredicateBuilder<Class> pb = Specifications.<Class>and()
                .like(StringUtils.isNotBlank(code), "code", "%" + code + "%")
                .like(StringUtils.isNotBlank(name), "name", "%" + name + "%")
                .eq(!StringUtils.isEmpty(grade), "grade", grade)
                .eq(StringUtils.isNotBlank(academyId), "academy.id", academyId)
                .eq(StringUtils.isNotBlank(professionId), "profession.id", professionId);
        Page<Class> entity = this.classRepository.findAll(pb.build(), PageHelper.generatePageRequest(page, size, sort));
        List<ClassDTO> classDtos = this.classMapper.toList(entity.getContent());
        return PageDataUtil.toPageData(entity, classDtos);
    }

    /**
     * 新增班级
     *
     * @param classDTO     班级信息
     * @return 新增班级
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ClassDTO create(ClassDTO classDTO) {
        // 获取学院
        Academy academy = this.getAcademyById(classDTO.getAcademyId());
        // 获取专业
        Profession profession = this.getProfessionById(classDTO.getProfessionId());
        Class aClass = this.classMapper.toEntity(classDTO);
        aClass.setAcademy(academy);
        aClass.setProfession(profession);
        Class save = this.classRepository.save(aClass);
        return this.classMapper.toDTO(save);
    }

    /**
     * 根据id获取学院
     *
     * @param id 学院id
     * @return 学院
     */
    private Academy getAcademyById(String id) {
        Optional<Academy> optionalAcademy = this.academyRepository.findById(Long.valueOf(id));
        if (!optionalAcademy.isPresent()) {
            throw new NoSuchDataException(id);
        }
        return optionalAcademy.get();
    }

    /**
     * 根据id获取专业
     *
     * @param id 专业id
     * @return 专业
     */
    private Profession getProfessionById(String id) {
        Optional<Profession> profession = this.professionRepository.findById(Long.valueOf(id));
        if (!profession.isPresent()) {
            throw new NoSuchDataException(id);
        }
        return profession.get();
    }

    /**
     * 删除班级
     *
     * @param id 班级id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(String id) {
        this.classRepository.deleteById(Long.valueOf(id));
    }

    /**
     * 更新班级信息
     *
     * @param id       班级id
     * @param classDTO 班级信息
     * @return 更新后班级信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ClassDTO update(String id, ClassDTO classDTO) {
        Class aClass = this.getOne(id);
        this.classMapper.updateEntity(classDTO, aClass);
        // 如果所属学院有变话，则修改所属学院
        if (!aClass.getAcademy().getId().equals(Long.valueOf(classDTO.getAcademyId()))) {
            Academy academy = this.getAcademyById(classDTO.getAcademyId());
            aClass.setAcademy(academy);
        }
        // 如果所属专业有变话，则修改所属专业
        if (!aClass.getProfession().getId().equals(Long.valueOf(classDTO.getProfessionId()))) {
            Profession profession = this.getProfessionById(classDTO.getAcademyId());
            aClass.setProfession(profession);
        }
        this.classRepository.save(aClass);
        return this.classMapper.toDTO(aClass);
    }

    /**
     * 根据id查找班级信息
     *
     * @param id 班级id
     * @param isGetStudent 是否获取学生
     * @return 班级信息
     */
    @Override
    public ClassDTO findById(String id, Boolean isGetStudent) {
        Class aClass = this.getOne(id);
        return isGetStudent ? this.classMapper.toDTO(aClass) : this.classMapper.toDtoByPage(aClass);
    }

    /**
     * 根据id获取班级
     *
     * @param id 班级id
     * @return 班级
     */
    private Class getOne(String id) {
        Optional<Class> optionalClass = this.classRepository.findById(Long.valueOf(id));
        if (!optionalClass.isPresent()) {
            throw new NoSuchDataException(id);
        }
        return optionalClass.get();
    }

    /**
     * 查找所有班级信息，可选择排序
     *
     * @param param   排序参数
     * @param pattern 排序模式: asc/desc
     * @return 班级信息
     */
    @Override
    public List<ClassDTO> findAll(String param, String pattern) {
        String keyType = "asc";
        Sort sort;
        if (keyType.equals(pattern)) {
            sort = new Sort(Sort.Direction.ASC, param);
        } else {
            sort = new Sort(Sort.Direction.DESC, param);
        }
        List<Class> all = this.classRepository.findAll(sort);
        return this.classMapper.toList(all);
    }

    /**
     * 检查班级code在本专业中是否已存在
     *
     * @param professionId 专业id
     * @param code         班级code
     * @return 是否存在
     */
    @Override
    public SimpleDataDTO<Boolean> checkCodeExist(String professionId, String code) {
        SimpleDataDTO<Boolean> simpleDataDTO = new SimpleDataDTO<>();
        Long id = this.classRepository.findByCodeAndOProfessionId(code, Long.valueOf(professionId));
        simpleDataDTO.setData(id != null);
        return simpleDataDTO;
    }

    /**
     * 统计班级数量
     *
     * @return 统计班级数量
     */
    @Override
    public Long countClass() {
        return this.classRepository.count();
    }
}